{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/aistudio/work\n"
     ]
    }
   ],
   "source": [
    "# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可:\r\n",
    "# Also add the following code, so that every time the environment (kernel) starts, just run the following code:\r\n",
    "import sys\r\n",
    "sys.path.append('/home/aistudio/work')\r\n",
    "import os\r\n",
    "os.chdir('/home/aistudio/work')\r\n",
    "print(os.getcwd())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/aistudio/work\n"
     ]
    }
   ],
   "source": [
    "\r\n",
    "#导入需要的包\r\n",
    "import paddle as paddle\r\n",
    "import paddle.fluid as fluid\r\n",
    "import numpy as np\r\n",
    "from PIL import Image\r\n",
    "import matplotlib.pyplot as plt\r\n",
    "import os\r\n",
    "import cv2\r\n",
    "\r\n",
    "print(os.getcwd())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1235\n",
      "./images/2_Disgust/94.jpg 1\n",
      "./images/6_Surprise/26.jpg 5\n"
     ]
    }
   ],
   "source": [
    "def reader_createor(im_list, label_list):\r\n",
    "    def reader():\r\n",
    "        for pt, lbl in zip(im_list, label_list):\r\n",
    "            im = cv2.imread(pt, 0)\r\n",
    "            im = cv2.resize(im, (128, 128))\r\n",
    "            if np.random.random() > 0.5:\r\n",
    "                im = cv2.flip(im, 1)\r\n",
    "            yield im, lbl\r\n",
    "    return reader\r\n",
    "\r\n",
    "base_pt = './images'\r\n",
    "datas = []\r\n",
    "labels = []\r\n",
    "label_list = []\r\n",
    "for i, cls in enumerate(os.listdir(base_pt)):\r\n",
    "    pt = os.path.join(base_pt, cls)\r\n",
    "    label_list.append(cls)\r\n",
    "    for im_pt in os.listdir(pt):\r\n",
    "        datas.append(os.path.join(pt, im_pt))\r\n",
    "        labels.append(i)\r\n",
    "\r\n",
    "np.random.seed(10)\r\n",
    "np.random.shuffle(datas)\r\n",
    "np.random.seed(10)\r\n",
    "np.random.shuffle(labels)\r\n",
    "\r\n",
    "print(len(datas))\r\n",
    "print(datas[0], labels[0])\r\n",
    "print(datas[600], labels[600])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\r\n",
    "BATCH_SIZE = 32\r\n",
    "#用于训练的数据提供器\r\n",
    "train_reader = paddle.batch(\r\n",
    "    paddle.reader.shuffle(\r\n",
    "        reader=reader_createor(datas[:-100], labels[:-100]),buf_size=200\r\n",
    "    ), batch_size=16\r\n",
    ")       \r\n",
    "test_reader = paddle.batch(\r\n",
    "    paddle.reader.shuffle(\r\n",
    "        reader=reader_createor(datas[-100:], labels[-100:]),buf_size=200\r\n",
    "    ), batch_size=16\r\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DistResNet():\r\n",
    "    def __init__(self, is_train=True):\r\n",
    "\r\n",
    "        self.is_train = is_train\r\n",
    "        self.weight_decay = 1e-4\r\n",
    "\r\n",
    "    def net(self, input, class_dim=10):\r\n",
    "    \r\n",
    "        depth = [3, 3, 3, 3, 3]\r\n",
    "        num_filters = [16, 16, 32, 32, 64]\r\n",
    "\r\n",
    "        conv = self.conv_bn_layer(\r\n",
    "            input=input, num_filters=16, filter_size=3, act='elu')\r\n",
    "        conv = fluid.layers.pool2d(\r\n",
    "            input=conv,\r\n",
    "            pool_size=3,\r\n",
    "            pool_stride=2,\r\n",
    "            pool_padding=1,\r\n",
    "            pool_type='max')\r\n",
    "\r\n",
    "        for block in range(len(depth)):\r\n",
    "            for i in range(depth[block]):\r\n",
    "                conv = self.bottleneck_block(\r\n",
    "                    input=conv,\r\n",
    "                    num_filters=num_filters[block],\r\n",
    "                    stride=2 if i == 0 and block != 0 else 1)\r\n",
    "                conv = fluid.layers.batch_norm(input=conv, act='elu')\r\n",
    "        print(conv.shape)\r\n",
    "        pool = fluid.layers.pool2d(\r\n",
    "            input=conv, pool_size=4, pool_type='avg', global_pooling=True)\r\n",
    "        stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)\r\n",
    "        out = fluid.layers.fc(input=pool,\r\n",
    "                              size=class_dim,\r\n",
    "                              act=\"softmax\",\r\n",
    "                              param_attr=fluid.param_attr.ParamAttr(\r\n",
    "                                  initializer=fluid.initializer.Uniform(-stdv,\r\n",
    "                                                                        stdv),\r\n",
    "                                  regularizer=fluid.regularizer.L2Decay(self.weight_decay)),\r\n",
    "                              bias_attr=fluid.ParamAttr(\r\n",
    "                                  regularizer=fluid.regularizer.L2Decay(self.weight_decay))\r\n",
    "                              )\r\n",
    "        return out\r\n",
    "\r\n",
    "    def conv_bn_layer(self,\r\n",
    "                      input,\r\n",
    "                      num_filters,\r\n",
    "                      filter_size,\r\n",
    "                      stride=1,\r\n",
    "                      groups=1,\r\n",
    "                      act=None,\r\n",
    "                      bn_init_value=1.0):\r\n",
    "        conv = fluid.layers.conv2d(\r\n",
    "            input=input,\r\n",
    "            num_filters=num_filters,\r\n",
    "            filter_size=filter_size,\r\n",
    "            stride=stride,\r\n",
    "            padding=(filter_size - 1) // 2,\r\n",
    "            groups=groups,\r\n",
    "            act=None,\r\n",
    "            bias_attr=False,\r\n",
    "            param_attr=fluid.ParamAttr(regularizer=fluid.regularizer.L2Decay(self.weight_decay)))\r\n",
    "        return fluid.layers.batch_norm(\r\n",
    "                input=conv, act=act, is_test=not self.is_train,\r\n",
    "                param_attr=fluid.ParamAttr(\r\n",
    "                    initializer=fluid.initializer.Constant(bn_init_value),\r\n",
    "                    regularizer=None))\r\n",
    "\r\n",
    "    def shortcut(self, input, ch_out, stride):\r\n",
    "        ch_in = input.shape[1]\r\n",
    "        if ch_in != ch_out or stride != 1:\r\n",
    "            return self.conv_bn_layer(input, ch_out, 1, stride)\r\n",
    "        else:\r\n",
    "            return input\r\n",
    "\r\n",
    "    def bottleneck_block(self, input, num_filters, stride):\r\n",
    "        conv0 = self.conv_bn_layer(\r\n",
    "            input=input, num_filters=num_filters, filter_size=1, act='elu')\r\n",
    "        conv1 = self.conv_bn_layer(\r\n",
    "            input=conv0,\r\n",
    "            num_filters=num_filters,\r\n",
    "            filter_size=3,\r\n",
    "            stride=stride,\r\n",
    "            act='elu')\r\n",
    "        conv2 = self.conv_bn_layer(\r\n",
    "            input=conv1, num_filters=num_filters * 4, filter_size=1, act=None, bn_init_value=0.0)\r\n",
    "\r\n",
    "        short = self.shortcut(input, num_filters * 4, stride)\r\n",
    "\r\n",
    "        return fluid.layers.elementwise_add(x=short, y=conv2, act='elu')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#定义输入数据\r\n",
    "data_shape = [1, 128, 128]\r\n",
    "images = fluid.layers.data(name='images', shape=data_shape, dtype='float32')\r\n",
    "label = fluid.layers.data(name='label', shape=[1], dtype='int64')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(-1, 256, 4, 4)\n",
      "(-1, 10) (-1, 1)\n"
     ]
    }
   ],
   "source": [
    "# 获取分类器，用cnn进行分类\r\n",
    "import math\r\n",
    "\r\n",
    "model =  DistResNet()\r\n",
    "predict = model.net(images)\r\n",
    "\r\n",
    "print(predict.shape, label.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 获取损失函数和准确率\r\n",
    "cost = fluid.layers.cross_entropy(input=predict, label=label) # 交叉熵\r\n",
    "avg_cost = fluid.layers.mean(cost)                            # 计算cost中所有元素的平均值\r\n",
    "acc = fluid.layers.accuracy(input=predict, label=label)       #使用输入和标签计算准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 定义优化方法\r\n",
    "optimizer =fluid.optimizer.Adam(learning_rate=2e-4)\r\n",
    "optimizer.minimize(avg_cost)\r\n",
    "\r\n",
    "place = fluid.CUDAPlace(0)\r\n",
    "exe = fluid.Executor(place)\r\n",
    "exe.run(fluid.default_startup_program())\r\n",
    "\r\n",
    "feeder = fluid.DataFeeder( feed_list=[images, label],place=place)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "iter=0\r\n",
    "iters=[]\r\n",
    "train_costs=[]\r\n",
    "train_accs=[]\r\n",
    "def draw_train_process(iters, train_costs, train_accs):\r\n",
    "    title=\"training costs/training accs\"\r\n",
    "    plt.title(title, fontsize=24)\r\n",
    "    plt.xlabel(\"iter\", fontsize=14)\r\n",
    "    plt.ylabel(\"cost/acc\", fontsize=14)\r\n",
    "    plt.plot(iters, train_costs, color='red', label='training costs')\r\n",
    "    plt.plot(iters, train_accs, color='green', label='training accs')\r\n",
    "    plt.legend()\r\n",
    "    plt.grid()\r\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "EPOCH_NUM = 20\r\n",
    "model_save_dir = \"/home/aistudio/data/emotion.inference.model\"\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pass:0, Batch:0, Cost:2.48173, Accuracy:0.00000\n"
     ]
    }
   ],
   "source": [
    "for pass_id in range(EPOCH_NUM):\r\n",
    "    # 开始训练\r\n",
    "    train_cost = 0\r\n",
    "    for batch_id, data in enumerate(train_reader()):    \r\n",
    "        train_cost,train_acc = exe.run(program=fluid.default_main_program(),\r\n",
    "                             feed=feeder.feed(data),              \r\n",
    "                             fetch_list=[avg_cost, acc])             \r\n",
    "        if batch_id % 100 == 0:                                          \r\n",
    "            # print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' % \r\n",
    "            # (pass_id, batch_id, train_cost[0], train_acc[0]))\r\n",
    "            print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' % \r\n",
    "            (pass_id, batch_id, np.mean(train_cost), np.mean(train_acc)))\r\n",
    "        iter=iter+BATCH_SIZE\r\n",
    "        iters.append(iter)\r\n",
    "        train_costs.append(np.mean(train_cost))\r\n",
    "        train_accs.append(np.mean(train_acc))\r\n",
    "    # 开始测试\r\n",
    "    test_costs = []                                                         #测试的损失值\r\n",
    "    test_accs = []                                                          #测试的准确率\r\n",
    "    for batch_id, data in enumerate(test_reader()):\r\n",
    "        test_cost, test_acc = exe.run(program=fluid.default_main_program(), #运行测试程序\r\n",
    "                                      feed=feeder.feed(data),               #喂入一个batch的数据\r\n",
    "                                      fetch_list=[avg_cost, acc])           #fetch均方误差、准确率\r\n",
    "        test_costs.append(test_cost[0])                                     #记录每个batch的误差\r\n",
    "        test_accs.append(test_acc[0])                                       #记录每个batch的准确率\r\n",
    "    test_cost = (sum(test_costs) / len(test_costs))                         #计算误差平均值（误差和/误差的个数）\r\n",
    "    test_acc = (sum(test_accs) / len(test_accs))                            #计算准确率平均值（ 准确率的和/准确率的个数）\r\n",
    "    print('Test:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, test_cost, test_acc))\r\n",
    "    \r\n",
    "    #保存模型\r\n",
    "    if not os.path.exists(model_save_dir):\r\n",
    "        os.makedirs(model_save_dir)\r\n",
    "    fluid.io.save_inference_model(model_save_dir,\r\n",
    "                                  ['images'],\r\n",
    "                                  [predict],\r\n",
    "                                  exe)\r\n",
    "print('训练模型保存完成！')\r\n",
    "draw_train_process(iters, train_costs,train_accs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "infer_exe = fluid.Executor(place)\r\n",
    "inference_scope = fluid.core.Scope() \r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from yolo3tiny.detection import Detector, draw_bbox, recover_img\r\n",
    "from PIL import ImageFont\r\n",
    "from PIL import Image\r\n",
    "from PIL import ImageDraw\r\n",
    "\r\n",
    "fontC = ImageFont.truetype('platech.ttf', 16, 0)\r\n",
    "\r\n",
    "\r\n",
    "def drawTest(image, addText, x1, y1):\r\n",
    "\r\n",
    "    img = Image.fromarray(image)\r\n",
    "    draw = ImageDraw.Draw(img)\r\n",
    "    draw.text((x1, y1),\r\n",
    "              addText.encode(\"utf-8\").decode(\"utf-8\"),\r\n",
    "              (0, 215, 255), font=fontC)\r\n",
    "    imagex = np.array(img)\r\n",
    "\r\n",
    "    return imagex\r\n",
    "\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def scale_img(img, IMG_WH=416):\r\n",
    "    if type(img) == str:\r\n",
    "        img = cv2.imread(img)\r\n",
    "    else:\r\n",
    "        if img.shape[0] < img.shape[1] and img.shape[0] < img.shape[2]:\r\n",
    "            img = img.swapaxes(0, 2).swapaxes(0, 1)\r\n",
    "    h, w, c = img.shape\r\n",
    "    dh, dh_e, dw, dw_e = 0, 0, 0, 0\r\n",
    "    if w > h:\r\n",
    "        dh = (w-h)//2\r\n",
    "        dh_e = w-h-dh-dh\r\n",
    "    else:\r\n",
    "        dw = (h-w)//2\r\n",
    "        dw_e = h-w-dw-dw\r\n",
    "    img = cv2.copyMakeBorder(img, dh, dh+dh_e, dw,\r\n",
    "                             dw+dw_e, cv2.BORDER_CONSTANT, value=[0, 0, 0])\r\n",
    "    imgArray = cv2.resize(img, (IMG_WH, IMG_WH))/255.0\r\n",
    "    return np.array(imgArray, dtype='float32').swapaxes(0, 2).swapaxes(1, 2)\r\n",
    "\r\n",
    "\r\n",
    "det = Detector(modelPath='./infer_model', USE_CUDA=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def draw_bbox(img, bboxes, color=(0, 0, 255)):\r\n",
    "    if type(img) == str:\r\n",
    "        img = cv2.imread(img)\r\n",
    "    else:\r\n",
    "        if img.shape[0] < img.shape[1] and img.shape[0] < img.shape[2]:\r\n",
    "            img = img.swapaxes(0, 2).swapaxes(0, 1)\r\n",
    "    if np.max(img) <= 1:\r\n",
    "        img *= 255\r\n",
    "    img = img.astype('uint8')\r\n",
    "    raw = img.copy()\r\n",
    "    rois = []\r\n",
    "    for bbox in bboxes:\r\n",
    "        x1, y1, x2, y2 = bbox[:4]\r\n",
    "        x1 = int(round(x1))\r\n",
    "        y1 = int(round(y1))\r\n",
    "        x2 = int(round(x2))\r\n",
    "        y2 = int(round(y2))\r\n",
    "        roi = raw[y1:y2, x1:x2]\r\n",
    "        rois.append(roi)\r\n",
    "        img = cv2.rectangle(img, (x1, y1), (x2, y2), color, 4)\r\n",
    "\r\n",
    "    return img, rois"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# im = cv2.imread('./faces/obama/obama.png')\r\n",
    "im = cv2.imread('a.png')\r\n",
    "im = scale_img(im, 416*2)\r\n",
    "\r\n",
    "bboxes_pre = det.detect(\r\n",
    "    im, confidence_threshold=0.99, nms_threshold=0.3)[0]\r\n",
    "\r\n",
    "result, rois = draw_bbox(im, bboxes_pre*2)\r\n",
    "\r\n",
    "print()\r\n",
    "\r\n",
    "plt.imshow(result[:, :, [2,1,0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def load_image(im):\r\n",
    "                # 打开图片\r\n",
    "        im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)\r\n",
    "\r\n",
    "        im = cv2.resize(im, (128, 128))\r\n",
    "        # 建立图片矩阵 类型为float32\r\n",
    "        im = np.array(im).astype(np.float32)\r\n",
    "        im = np.expand_dims(im, axis=0)\r\n",
    "        im = np.expand_dims(im, axis=0)\r\n",
    "        # 保持和之前输入image维度一致\r\n",
    "        print('im_shape的维度：', im.shape)\r\n",
    "        return im"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(label_list)\r\n",
    "\r\n",
    "with fluid.scope_guard(inference_scope):\r\n",
    "    #从指定目录中加载 推理model(inference model)\r\n",
    "    [inference_program, # 预测用的program\r\n",
    "     feed_target_names, # 是一个str列表，它包含需要在推理 Program 中提供数据的变量的名称。 \r\n",
    "     fetch_targets] = fluid.io.load_inference_model(model_save_dir,#fetch_targets：是一个 Variable 列表，从中我们可以得到推断结果。\r\n",
    "                                                    infer_exe)     #infer_exe: 运行 inference model的 executor\r\n",
    "    \r\n",
    "    img = load_image(rois[0])\r\n",
    "\r\n",
    "    results = infer_exe.run(inference_program,                 #运行预测程序\r\n",
    "                            feed={feed_target_names[0]: img},  #喂入要预测的img\r\n",
    "                            fetch_list=fetch_targets)          #得到推测结果\r\n",
    "\r\n",
    "    plt.imshow(rois[0][:, :, [2,1,0]])   \r\n",
    "    plt.title(\"infer results: %s\" % label_list[np.argmax(results[0])])\r\n",
    "    plt.show()   "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "PaddlePaddle 1.7.1 (Python 3.5)",
   "language": "python",
   "name": "py35-paddle1.2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
